// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/runtime/dart_plugin_registrant.h"

#include <string>

#include "flutter/fml/trace_event.h"
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/logging/dart_invoke.h"

namespace flutter {

namespace {
bool EndsWith(const std::string& str, const std::string& ending) {
  if (str.size() >= ending.size()) {
    return (0 ==
            str.compare(str.size() - ending.size(), ending.size(), ending));
  } else {
    return false;
  }
}

Dart_Handle FindDartPluginRegistrantLibrary() {
  // TODO(99308): Instead of finding this, it could be passed down from the
  // tool.
  Dart_Handle libraries = Dart_GetLoadedLibraries();
  intptr_t length = 0;
  Dart_ListLength(libraries, &length);
  for (intptr_t i = 0; i < length; ++i) {
    Dart_Handle library = Dart_ListGetAt(libraries, i);
    std::string library_name =
        tonic::DartConverter<std::string>::FromDart(Dart_ToString(library));
    if (EndsWith(library_name,
                 "dart_tool/flutter_build/dart_plugin_registrant.dart'")) {
      return library;
    }
  }
  return Dart_Null();
}
}  // namespace

bool InvokeDartPluginRegistrantIfAvailable(Dart_Handle library_handle) {
  TRACE_EVENT0("flutter", "InvokeDartPluginRegistrantIfAvailable");

  // The Dart plugin registrant is a static method with signature `void
  // register()` within the class `_PluginRegistrant` generated by the Flutter
  // tool.
  //
  // This method binds a plugin implementation to their platform
  // interface based on the configuration of the app's pubpec.yaml, and the
  // plugin's pubspec.yaml.
  //
  // Since this method may or may not be defined, check if the class is defined
  // in the default library before calling the method.
  Dart_Handle plugin_registrant =
      ::Dart_GetClass(library_handle, tonic::ToDart("_PluginRegistrant"));

  if (Dart_IsError(plugin_registrant)) {
    return false;
  }
  tonic::LogIfError(tonic::DartInvokeField(plugin_registrant, "register", {}));
  return true;
}

bool FindAndInvokeDartPluginRegistrant() {
  auto dart_plugin_registrant_library = FindDartPluginRegistrantLibrary();
  if (!Dart_IsNull(dart_plugin_registrant_library)) {
    return InvokeDartPluginRegistrantIfAvailable(
        dart_plugin_registrant_library);
  } else {
    return false;
  }
}
}  // namespace flutter
